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}