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 <string>
21
22 #include <securec.h>
23 #include <unistd.h>
24
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28 #include <sys/un.h>
29
30 #include "dfx_define.h"
31 #include "dfx_log.h"
32 #include "init_socket.h"
33
34 namespace {
35 constexpr int SOCKET_BUFFER_SIZE = 32;
36 }
37
StartConnect(int32_t sockFd,const char * socketName,uint32_t timeout)38 bool StartConnect(int32_t sockFd, const char* socketName, uint32_t timeout)
39 {
40 if (UNLIKELY(sockFd < 0 || socketName == nullptr)) {
41 return false;
42 }
43 if (timeout > 0) {
44 struct timeval timev = { timeout, 0 };
45 if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev))) != 0) {
46 DFXLOGE("setsockopt(%{public}d) SO_RCVTIMEO error, errno(%{public}d).", sockFd, errno);
47 }
48 if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockFd, SOL_SOCKET, SO_SNDTIMEO, &timev, sizeof(timev))) != 0) {
49 DFXLOGE("setsockopt(%{public}d) SO_SNDTIMEO error, errno(%{public}d).", sockFd, errno);
50 }
51 }
52
53 struct sockaddr_un server{0};
54 server.sun_family = AF_LOCAL;
55 std::string fullPath = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(socketName);
56 errno_t err = strncpy_s(server.sun_path, sizeof(server.sun_path), fullPath.c_str(), sizeof(server.sun_path) - 1);
57 if (err != EOK) {
58 DFXLOGE("%{public}s :: strncpy failed, err = %{public}d.", __func__, (int)err);
59 return false;
60 }
61
62 int len = static_cast<int>(offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path) + 1);
63 int connected = OHOS_TEMP_FAILURE_RETRY(connect(sockFd, reinterpret_cast<struct sockaddr *>(&server), len));
64 if (connected < 0) {
65 DFXLOGE("%{public}s :: connect failed, errno = %{public}d.", __func__, errno);
66 return false;
67 }
68 return true;
69 }
70
CreateSocketFd()71 int32_t CreateSocketFd()
72 {
73 int32_t socketFd = socket(AF_LOCAL, SOCK_STREAM, 0);
74 if (socketFd < 0) {
75 DFXLOGE("%{public}s :: Failed to create socket, errno(%{public}d)", __func__, errno);
76 return -1;
77 }
78 return socketFd;
79 }
80
GetServerSocket(int32_t & sockFd,const char * name)81 static bool GetServerSocket(int32_t& sockFd, const char* name)
82 {
83 sockFd = OHOS_TEMP_FAILURE_RETRY(socket(AF_LOCAL, SOCK_STREAM, 0));
84 if (sockFd < 0) {
85 DFXLOGE("%{public}s :: Failed to create socket, errno(%{public}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{0};
91 server.sun_family = AF_LOCAL;
92 if (strncpy_s(server.sun_path, sizeof(server.sun_path), path.c_str(), sizeof(server.sun_path) - 1) != 0) {
93 DFXLOGE("%{public}s :: strncpy failed.", __func__);
94 return false;
95 }
96
97 chmod(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH);
98 unlink(path.c_str());
99
100 int optval = 1;
101 int ret = OHOS_TEMP_FAILURE_RETRY(setsockopt(sockFd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)));
102 if (ret < 0) {
103 DFXLOGE("%{public}s :: Failed to set socket option, errno(%{public}d)", __func__, errno);
104 return false;
105 }
106
107 if (bind(sockFd, reinterpret_cast<struct sockaddr *>(&server),
108 offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path)) < 0) {
109 DFXLOGE("%{public}s :: Failed to bind socket, errno(%{public}d)", __func__, errno);
110 return false;
111 }
112
113 return true;
114 }
115
StartListen(int32_t & sockFd,const char * name,uint32_t listenCnt)116 bool StartListen(int32_t& sockFd, const char* name, uint32_t listenCnt)
117 {
118 if (name == nullptr) {
119 return false;
120 }
121 sockFd = GetControlSocket(name);
122 if (sockFd < 0) {
123 DFXLOGW("%{public}s :: Failed to get socket fd by cfg", __func__);
124 if (!GetServerSocket(sockFd, name)) {
125 DFXLOGE("%{public}s :: Failed to get socket fd by path", __func__);
126 return false;
127 }
128 }
129
130 if (listen(sockFd, listenCnt) < 0) {
131 DFXLOGE("%{public}s :: Failed to listen socket, errno(%{public}d)", __func__, errno);
132 close(sockFd);
133 sockFd = -1;
134 return false;
135 }
136
137 DFXLOGI("%{public}s :: success to listen socket %{public}s", __func__, name);
138 return true;
139 }
140
RecvMsgFromSocket(int sockFd,void * data,const size_t dataLength)141 static bool RecvMsgFromSocket(int sockFd, void* data, const size_t dataLength)
142 {
143 if (sockFd < 0 || data == nullptr) {
144 return false;
145 }
146
147 struct msghdr msgh{0};
148 char msgBuffer[SOCKET_BUFFER_SIZE] = { 0 };
149 struct iovec iov = {
150 .iov_base = msgBuffer,
151 .iov_len = sizeof(msgBuffer)
152 };
153 msgh.msg_iov = &iov;
154 msgh.msg_iovlen = 1;
155
156 char ctlBuffer[SOCKET_BUFFER_SIZE] = { 0 };
157 msgh.msg_control = ctlBuffer;
158 msgh.msg_controllen = sizeof(ctlBuffer);
159
160 if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockFd, &msgh, 0)) < 0) {
161 DFXLOGE("%{public}s :: Failed to recv message, errno(%{public}d)", __func__, errno);
162 return false;
163 }
164
165 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
166 if (cmsg == nullptr) {
167 DFXLOGE("%{public}s :: Invalid message", __func__);
168 return false;
169 }
170 if (dataLength != cmsg->cmsg_len - sizeof(struct cmsghdr)) {
171 DFXLOGE("%{public}s :: msg length is not matched", __func__);
172 return false;
173 }
174 if (memcpy_s(data, dataLength, CMSG_DATA(cmsg), dataLength) != 0) {
175 DFXLOGE("%{public}s :: memcpy error", __func__);
176 return false;
177 }
178 return true;
179 }
180
SendMsgCtlToSocket(int sockFd,const void * cmsg,uint32_t cmsgLen)181 static bool SendMsgCtlToSocket(int sockFd, const void *cmsg, uint32_t cmsgLen)
182 {
183 if ((sockFd < 0) || (cmsg == nullptr) || (cmsgLen == 0)) {
184 return false;
185 }
186
187 struct msghdr msgh{0};
188 char iovBase[] = "";
189 struct iovec iov = {.iov_base = iovBase, .iov_len = 1};
190 msgh.msg_iov = &iov;
191 msgh.msg_iovlen = 1;
192
193 int controlBufLen = CMSG_SPACE(cmsgLen);
194 char controlBuf[controlBufLen];
195 msgh.msg_control = controlBuf;
196 msgh.msg_controllen = sizeof(controlBuf);
197
198 struct cmsghdr *cmsgh = CMSG_FIRSTHDR(&msgh);
199 if (cmsgh != nullptr) {
200 cmsgh->cmsg_level = SOL_SOCKET;
201 cmsgh->cmsg_type = SCM_RIGHTS;
202 cmsgh->cmsg_len = CMSG_LEN(cmsgLen);
203 if (memcpy_s(CMSG_DATA(cmsgh), cmsgLen, cmsg, cmsgLen) != 0) {
204 DFXLOGE("%{public}s :: memcpy error", __func__);
205 }
206 }
207
208 if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockFd, &msgh, 0)) < 0) {
209 DFXLOGE("%{public}s :: Failed to send message, errno(%{public}d)", __func__, errno);
210 return false;
211 }
212 return true;
213 }
214
SendFileDescriptorToSocket(int32_t sockFd,const int32_t * fds,uint32_t nFds)215 bool SendFileDescriptorToSocket(int32_t sockFd, const int32_t* fds, uint32_t nFds)
216 {
217 if (nFds == 0 || fds == nullptr) {
218 return false;
219 }
220 return SendMsgCtlToSocket(sockFd, fds, sizeof(int32_t) * nFds);
221 }
222
ReadFileDescriptorFromSocket(int32_t sockFd,int32_t * fds,uint32_t nFds)223 bool ReadFileDescriptorFromSocket(int32_t sockFd, int32_t* fds, uint32_t nFds)
224 {
225 if (nFds == 0 || fds == nullptr) {
226 return false;
227 }
228 if (!RecvMsgFromSocket(sockFd, fds, sizeof(int32_t) * nFds)) {
229 DFXLOGE("%{public}s :: Failed to recv message", __func__);
230 return false;
231 }
232 return true;
233 }
234
SendMsgToSocket(int32_t sockFd,const void * data,uint32_t dataLength)235 bool SendMsgToSocket(int32_t sockFd, const void* data, uint32_t dataLength)
236 {
237 if (data == nullptr || sockFd < 0 || dataLength == 0) {
238 DFXLOGE("Failed to write request message to socket, invalid data or socket fd %{public}d.", sockFd);
239 return false;
240 }
241 if (OHOS_TEMP_FAILURE_RETRY(write(sockFd, data, dataLength)) != dataLength) {
242 DFXLOGE("Failed to write request message to socket, errno(%{public}d).", errno);
243 return false;
244 }
245 return true;
246 }
247
GetMsgFromSocket(int32_t sockFd,void * data,uint32_t dataLength)248 bool GetMsgFromSocket(int32_t sockFd, void* data, uint32_t dataLength)
249 {
250 if (data == nullptr || sockFd < 0 || dataLength == 0) {
251 DFXLOGE("Failed to read message from socket, invalid data or socket fd %{public}d.", sockFd);
252 return false;
253 }
254 ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(sockFd, data, dataLength));
255 if (nread <= 0) {
256 DFXLOGE("Failed to get message from socket, %{public}zd.", nread);
257 return false;
258 }
259 return true;
260 }